home *** CD-ROM | disk | FTP | other *** search
/ PC-X 1997 October / pcx14_9710.iso / swag / delphi.swg / 0082_More on using TStream-TFileStream.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-11-24  |  4.1 KB  |  104 lines

  1.  
  2. Take a look at TStream/TFileStream.  There is a specific pair of methods
  3. called WriteComponent and ReadComponent that will do what you need.
  4. However, it may not always work exactly as expected.
  5.  
  6. WriteComponent will take a component as a parameter and will write
  7. that component and all components that it owns to a stream, according
  8. to the documentation.  However, it will not actually write all of
  9. its owned components unless it is a TWinControl descendant (or a
  10. component type that overrides the WriteComponents method).
  11.  
  12. To store a form and all of the components on it, you would do something
  13. like:
  14.  
  15. procedure SaveForm(form : TForm; filename : string);
  16. var
  17.   fstream : TFileStream;
  18. begin
  19.   if form <> nil then begin
  20.     fstream := TFileStream.Create(filename, fmCreate);
  21.     try
  22.       fstream.WriteComponent(form);
  23.     finally
  24.       fstream.Free;
  25.     end;
  26.   end;
  27. end;
  28.  
  29. You could then read it back in with the following:
  30.  
  31. function LoadForm(filename : string) : TForm;
  32. var
  33.   fstream : TFileStream;
  34.   cmpnt   : TComponent;
  35. begin
  36.   Result  := nil;
  37.   fstream := TFileStream.Create(OpenDialog1.FileName, fmOpenRead);
  38.   try
  39.     cmpnt := fstream.ReadComponent(nil);   {read component from stream}
  40.     if cmpnt <> nil then begin             {if successfully read, ... }
  41.       if cmpnt is TForm then begin         {check that it is a form   }
  42.         Result := cmpnt;                   {if so, return it          }
  43.         Application.InsertComponent(Result); {and make App owner of it}
  44.       end else                             {if not what was expected  }
  45.         cmpnt.Free;                        {free it and return nil    }
  46.     end;
  47.   finally
  48.     fstream.Free;
  49.   end;
  50. end;
  51.  
  52. One thing you should watch out for, however, is that this method writes
  53. and reads ALL of the components on the form, even those that were added
  54. during design time.  This can be problematic when you try to read the
  55. form back in.  The first item read in will be the form itself, which
  56. will be created according to its declaration, which will include all
  57. of the controls added at design time.  Then, when it begins loading
  58. in the owned controls from the stream, it will run into name conflicts
  59. when it tries to create those controls that were design-time additions
  60. to the form since they already exist when the form is created.
  61.  
  62. One possible way around this is to limit exactly which components
  63. are saved to the stream.  For example, something like this:
  64.  
  65.         for i := 0 to form.ComponentCount - 1 do
  66.           fstream.WriteComponent(form.Components[i]);
  67.  
  68. This will store one component after another to the stream.  You could
  69. then read it back with something like:
  70.  
  71.       while not (fstream.Position = fstream.Size) do begin
  72.         cmpnt := fstream.ReadComponent(nil);
  73.         if cmpnt <> nil then begin
  74.           form.InsertComponent(cmpnt);
  75.           if cmpnt is TControl then
  76.             TControl(cmpnt).Parent := form;
  77.         end;
  78.       end;
  79.  
  80. However, watch out when you use this.  It is not compatible with some
  81. components.  For example, when I tried to use this method to load in
  82. a TMemo I had saved that contained some text, I received a 'Control
  83. has no parent' exception.  Apparently, attempting to add text to a
  84. TMemo that has no Parent will cause an exception, interrupting the
  85. ReadComponent process.
  86.  
  87. With a bit more work and code, you may be able to come up with a
  88. more flexible method for loading and saving components.  To do so,
  89. you will need to take a look at the TFiler components, TReader and
  90. TWriter.
  91.  
  92. Oh!  One other note -- ReadComponent and WriteComponent will only
  93. work with components that have been registered with a call to
  94. RegisterClass or RegisterClasses.  It uses the list of registered
  95. classes as a look-up table to determine how to recreate what is
  96. stored in the stream.  Unforutnately, Delphi does not automatically
  97. register classes.  So, you must already have some idea ahead of
  98. time about what kinds of controls may be read and written.  Make
  99. a call to RegisterClasses once during application start-up --
  100. something like:
  101.  
  102.   RegisterClasses([TButton, TEdit, TListBox, TMemo, TForm1]);
  103.  
  104.